package cn.bonoon.kernel.web.handlers.loader;

import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.List;

import cn.bonoon.kernel.annotations.QueryExpression;
import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.expression.QueryExpressionParameter;
import cn.bonoon.kernel.expression.WhereExpressionWrapper;
import cn.bonoon.kernel.filters.AutoLoadFilter;
import cn.bonoon.kernel.filters.InitLoadFilter;
import cn.bonoon.kernel.filters.StandardAutoLoadFilter;
import cn.bonoon.kernel.support.ProxyEntityManager;
import cn.bonoon.kernel.support.searcher.Finder;
import cn.bonoon.kernel.support.searcher.ISearcher;
import cn.bonoon.kernel.support.searcher.StandardFinder;
import cn.bonoon.kernel.web.handlers.AbstractExecuteHandler;

/**
 * 加载数据的父类
 * @author jackson
 *
 */
public abstract class AbstractLoaderHandler extends AbstractExecuteHandler{
	
	private final IQueryParameterBuilder parameter;

	protected WhereExpressionWrapper expressionParser;

	protected List<AutoLoadFilter> filters = new ArrayList<>();

	protected final ISearcher searcher;
	
	protected final EntityDescriptor entityDescriptor;
	
	protected final ProxyEntityManager entityManager;
	
	protected AbstractLoaderHandler(ISearcher searcher, ProxyEntityManager entityManager, Class<?> queryClass) throws Exception{
		super("ajax");
		if(null == queryClass){
			this.parameter = IQueryParameterBuilder.EMPTY;
		}else{
			this.parameter = new StandardQueryParameterBuilder(queryClass, searcher).init();
		}
		this.searcher = searcher;
		this.entityDescriptor = searcher.getEntityDescriptor();
		this.entityManager = entityManager;
	}

//	protected AbstractLoaderHandler(ISearcher searcher, ProxyEntityManager entityManager) throws Exception{
//		super("ajax");
//		this.parameter = IQueryParameterBuilder.EMPTY;
//		this.searcher = searcher;
//		this.entityDescriptor = searcher.getEntityDescriptor();
//		this.entityManager = entityManager;
//	}

	protected void parseFilter(boolean useDefaultFilter, Class<? extends InitLoadFilter>[] values, AnnotatedElement ele){
		
		if(useDefaultFilter){
			defaultFilter();
		}
		
		for(Class<? extends InitLoadFilter> val : values){
			try{
				InitLoadFilter ilf = val.newInstance();
				filters.add(ilf.init(ele, entityDescriptor));
			}catch(Throwable th){
				logger.warn("解析过滤器时异常，无法使用该过滤器！", th);
			}
		}
	}
	
	protected void defaultFilter(){
		filters.add(new StandardAutoLoadFilter(entityDescriptor));
	}
	
	public void addFilter(AutoLoadFilter alFilter){
		filters.add(alFilter);
	}
	
	public List<QueryExpressionParameter> getParameters() {
		if(null == expressionParser) return null;
		
		return expressionParser.getParameters();
	}
	
	public WhereExpressionWrapper getExpressionParser() {
		_checked();
		return expressionParser;
	}
	
	public void addExpression(QueryExpression expression) throws Exception{
		_checked();
		this.expressionParser.add(expression);
	}
	
	public void addExpression(String expression) throws Exception{
		_checked();
		this.expressionParser.add(expression);
	}

	public void addExpression(String expression, String value) throws Exception{
		_checked();
		this.expressionParser.add(expression, value);
	}
	
	private void _checked(){
		if(null == this.expressionParser){
			this.expressionParser = new WhereExpressionWrapper();
		}
	}

	protected abstract Object __parseResult(Finder finder, ReadEvent event)throws Exception;

	public final Object execute(ReadEvent event) throws Exception{
		StandardFinder finder = buildFinder(event);
		parseQuery(finder, event);
		return __parseResult(finder, event);
	}
	
	/**
	 * 用来解析查询条件，子类可以重写，添加更多的对查询条件的处理
	 * @param finder
	 * @param event
	 */
	protected void parseQuery(StandardFinder finder, ReadEvent event)throws Exception{
		finder.combineExpression(expressionParser);
		
		Object cond = event.getSource();
		parameter.query(finder, cond);
		finder.parseExpression(event);
		
		if(cond instanceof AutoLoadFilter){
			((AutoLoadFilter) cond).filter(finder, event);
		}
		
		if(null != filters){
			for(AutoLoadFilter filter : filters){
				filter.filter(finder, event);
			}
		}
	}
	
	@Override
	public Object buildParams() {
		return parameter.instance();
	}

	protected StandardFinder buildFinder(ReadEvent event)throws Exception{
		return searcher.finder(entityManager);
	}
	
}
